//; ---------------------------------------------------------------------------
//; Object 26 - monitors
//; ---------------------------------------------------------------------------

#include "monitor.h"

#include "explosions.h"
#include "powerup.h"

#include "../sprite.h"
#include "../objectsystemNEWER.h"

#include "../collision.h"

static object *obj;

#define player objects[0]
extern object *objects;

extern byte v_objstate[];  //object state list, used in objectsystem.c

extern bool f_lockmulti;

extern word v_debuguse;

//; ---------------------------------------------------------------------------
//; Animation script - monitors
//; ---------------------------------------------------------------------------
byte _static[5] = { 1, 0, 1, 2, afEnd };
byte eggman[11] = { 1, 0, 3, 3, 1, 3, 3, 2, 3,	3, afEnd };
byte sonic[11] =  { 1, 0, 4, 4, 1, 4, 4, 2, 4,	4, afEnd };
byte shoes[11] =  { 1, 0, 5, 5, 1, 5, 5, 2, 5,	5, afEnd };
byte shield[11] = { 1, 0, 6, 6, 1, 6, 6, 2, 6,	6, afEnd };
byte invincible[11] = { 1, 0, 7, 7, 1, 7, 7, 2, 7, 7, afEnd };
byte rings[11] =  { 1, 0, 8, 8, 1, 8, 8, 2, 8,	8, afEnd };
byte s[11] =      { 1, 0, 9, 9, 1, 9, 9, 2, 9,	9, afEnd };
byte goggles[11] = { 1, 0, 0xA, 0xA, 1, 0xA, 0xA, 2, 0xA, 0xA, afEnd };
byte breaking[7] = { 2,	0, 1, 2, 0xB, afBack, 1 };
		
byte *Ani_Monitor[10] = { _static, eggman, sonic, shoes, shield, invincible, rings, s, goggles, breaking };

//; ---------------------------------------------------------------------------
//; Sprite mappings - monitors
//; ---------------------------------------------------------------------------
byte static0[6] = { 1, 			 //; static monitor
		 0xEF, 0xF, 0, 0, 0xF0
};
byte static1[11] = { 2,			 //; static monitor
		 0xF5,   5, 0, 0x10, 0xF8,
		 0xEF, 0xF, 0,    0, 0xF0
};
byte static2[11] = { 2,			 //; static monitor
		 0xF5,   5, 0, 0x14,  0xF8,
                 0xEF, 0xF, 0,    0,  0xF0
};
byte _eggman[11] = { 2,			 //; Eggman monitor
		 0xF5,   5, 0, 0x18, 0xF8,
		 0xEF, 0xF, 0,    0, 0xF0
};
byte _sonic[11] = { 2,			 //; Sonic	monitor
		0xF5,   5, 0, 0x1C, 0xF8,
		0xEF, 0xF, 0,    0, 0xF0
};
byte _shoes[11]	= { 2,			 //; speed	shoes monitor
		0xF5,   5, 0, 0x24, 0xF8,
		0xEF, 0xF, 0,    0, 0xF0
};
byte _shield[11] = { 2,			 //; shield monitor
		0xF5,   5, 0, 0x28, 0xF8,
		0xEF, 0xF, 0,    0, 0xF0
};
byte _invincible[11] = { 2,		 //; invincibility	monitor
		0xF5,   5, 0, 0x2C, 0xF8,
		0xEF, 0xF, 0,    0, 0xF0
};
byte _rings[11]	 = { 2,			 //; 10 rings monitor
		0xF5,   5, 0, 0x30, 0xF8,
		0xEF, 0xF, 0,    0, 0xF0
};
byte _s[11]	 = { 2,			 //; 'S' monitor
		0xF5,   5, 0, 0x34, 0xF8,
		0xEF, 0xF, 0,    0, 0xF0
};
byte _goggles[11] ={ 2,			 //; goggles monitor
		0xF5,   5, 0, 0x20, 0xF8,
		0xEF, 0xF, 0,    0, 0xF0
};
byte _broken[6] =  { 1,			 //; broken monitor
		0xFF, 0xD, 0, 0x38, 0xF0
};

byte *Map_Monitor[12] = { static0, static1, static2, _eggman, _sonic, _shoes, _shield, _invincible, _rings, _s, _goggles, _broken };

//----
void (*Mon_Index[5])() = { Mon_Main, Mon_Solid, Mon_BreakOpen, Mon_Animate, Mon_Display };

//Monitor:				; XREF: Obj_Index
void Monitor(object *_obj)
{
    obj = _obj;                         //standard

    //moveq	#0,d0
    //move.b	obRoutine(a0),d0          standard
    byte routine = obj->Routine/2;

    //move.w	HUD_Index(pc,d0.w),d1
    //jmp	HUD_Index(pc,d1.w)
    (*Mon_Index[routine])();
}


//Mon_Main:	; Routine 0
void Mon_Main()
{
    //addq.b	#2,obRoutine(a0)          standard
    obj->Routine = obj->Routine + 2;

    //move.b	#$E,obHeight(a0)          w/h most likely standard
    obj->Height = 0xE;

    //move.b	#$E,obWidth(a0)
    obj->Width = 0xE;

    //move.l	#Map_Monitor,obMap(a0)
    obj->Map = Map_Monitor;              //mappings 
                                         //
    //move.w	#$680,obGfx(a0)          //and
    obj->Gfx = 0x680;                    //graphics  standard for object


    //move.b	#4,obRender(a0)
    obj->Render = 4;

    //move.b	#3,obPriority(a0)
    obj->Priority = 3;

    //move.b	#$F,obActWid(a0)
    obj->ActionWidth = 0xF;

    //CLEAR BIT 7 FOR THIS PARTICULAR MONITOR (respawnno) IN STATE LIST
    //lea	(v_objstate).w,a2
    byte *statePtr = v_objstate;

    //moveq	#0,d0
    //move.b	obRespawnNo(a0),d0
    byte respawn = obj->RespawnNo;

    #define curMonitor 2+respawn
    //bclr	#7,2(a2,d0.w)
    statePtr[curMonitor] = statePtr[curMonitor] - (statePtr[curMonitor] & 0x80);


    //btst	#0,2(a2,d0.w)	; has monitor been broken?
    //beq.s	@notbroken	; if not, branch
    if ((statePtr[curMonitor] & 1) == 1)
    {
        //move.b	#8,obRoutine(a0) ; run "Mon_Display" routine
        obj->Routine = 8;

	//move.b	#$B,obFrame(a0)	; use broken monitor frame
        obj->Frame = 0xB;

    }    //rts	
    else
    {
        //; ===========================================================================
	//@notbroken:
	//move.b	#$46,obColType(a0)
        obj->ColType = 0x46;

	//move.b	obSubtype(a0),obAnim(a0)
        obj->Anim = obj->Subtype;
    
        Mon_Solid();
    }   
}

//Mon_Solid:	; Routine 2
void Mon_Solid()
{
    //move.b	ob2ndRout(a0),d0 ; is monitor set to fall?
    byte monitorRoutine = obj->secondRoutine;

    //beq.s	@normal		; if not, branch
    if (monitorRoutine != 0)
    {
        //subq.b	#2,d0
        byte monitorMove = monitorRoutine - 2;

	//bne.s	@fall
        if (monitorMove == 0)
        {
            //; 2nd Routine 2
	    //moveq	#0,d1
	    //move.b	obActWid(a0),d1
            //addi.w	#$B,d1
            byte actionWidth = obj->ActionWidth + 0xB;

            signed short platDist;
	    //bsr.w	ExitPlatform
            ExitPlatform(obj, actionWidth, platDist);

	    //btst	#3,obStatus(a1) ; is Sonic on top of the monitor?
            //bne.w	@ontop		; if yes, branch
            if ((player.Status & 8) == 0)
            {
                //clr.b	ob2ndRout(a0)
		obj->secondRoutine = 0;

		//bra.w	Mon_Animate
                Mon_Animate();
            }
            else
            {
                //; ===========================================================================

	        //@ontop:
		/*move.w	#$10,d3
                move.w	obX(a0),d2
		bsr.w	MvSonicOnPtfm*/
		
                //bra.w	Mon_Animate
                Mon_Animate();
            
            }   //; ===========================================================================

        }
        else
        {   

            //@fall:		; 2nd Routine 4
		
            //bsr.w	ObjectFall
            ObjectFall(obj);

	    //jsr	ObjFloorDist
            signed short floorDist = ObjFloorDist(obj);

	    //tst.w	d1
	    //bpl.w	Mon_Animate
            if (floorDist >= 0) { Mon_Animate(); }
	    else
            {
                //add.w	d1,obY(a0)
                obj->Y = obj->Y + floorDist;

	        //clr.w	obVelY(a0)
                obj->VelocityY = 0;

	        //clr.b	ob2ndRout(a0)
                obj->secondRoutine = 0;

	        //bra.w	Mon_Animate
                Mon_Animate();
            }
        }   //; ===========================================================================
    }
    else
    {
        //@normal:	; 2nd Routine 0
        /*move.w	#$1A,d1
        move.w	#$F,d2
        bsr.w	Mon_SolidSides*/
        signed short distPlayerMonX, distPlayerMonY;
        signed short sidesFlag = Mon_SolidSides(obj, 0x1A, 0xF, distPlayerMonX, distPlayerMonY);

        //beq.w	loc_A25C
        //tst.w	obVelY(a1)
        //bmi.s	loc_A20A
        //cmpi.b	#id_Roll,obAnim(a1) ; is Sonic rolling?
        //beq.s	loc_A25C	; if yes, branch
        if ((sidesFlag == 0) || ((player.VelocityY >=0) && (player.Anim == id_Roll)))
        {
            //loc_A25C:
	    //btst	#5,obStatus(a0)
            //beq.s	Mon_Animate
            if ((obj->Status & 32) == 0)     //monitor not being pushed
                Mon_Animate();
	    else
            {
	        //move.w	#1,obAnim(a1)
                player.Anim = 1;

                //loc_A26A:
	        //bclr	#5,obStatus(a0)
                obj->Status = obj->Status - (obj->Status & 32);

	        //bclr	#5,obStatus(a1)
                player.Status = player.Status - (player.Status & 32);

                Mon_Animate();
            }
        }
        else
        {
            //loc_A20A:
	    //tst.w	d1
            //bpl.s	loc_A220
            if (sidesFlag < 0)
            {
	        //sub.w	d3,obY(a1)
                player.Y = player.Y - distPlayerMonY; 

	        //bsr.w	loc_74AE
                loc_74AE(obj);        ////inPlatformObject
                
	        //move.b	#2,ob2ndRout(a0)
                obj->secondRoutine = 2;

	        //bra.w	Mon_Animate
                Mon_Animate();
            }
        
            //; ===========================================================================
            else
            {
                //loc_A220:
	        //tst.w	d0
                //beq.w	loc_A246
                //bmi.s	loc_A230
                //tst.w	obVelX(a1)
                //bmi.s	loc_A246
	        //bra.s	loc_A236
                //loc_A230:
	        //tst.w	obVelX(a1)
	        //bpl.s	loc_A246
                if (distPlayerMonX != 0)
                {
                    if (((distPlayerMonX < 0) && (player.VelocityX < 0)) || ((distPlayerMonX >= 0) && (player.VelocityX >= 0)))
                    {
                        //loc_A236:
		        //sub.w	d0,obX(a1)
                        player.X = player.X - distPlayerMonX;

		        //move.w	#0,obInertia(a1)
                        player.Inertia = 0;

		        //move.w	#0,obVelX(a1)
                        player.VelocityX = 0;
                    }
		
                }   //; ===========================================================================
                   
                //loc_A246:
	        //btst	#1,obStatus(a1)
                //bne.s	loc_A26A
                if ((player.Status & 2) == 2)  //sonic jumping?
                { 
	            //loc_A26A:
	            //bclr	#5,obStatus(a0)
                    obj->Status = obj->Status - (obj->Status & 32);

	            //bclr	#5,obStatus(a1)
                    player.Status = player.Status - (player.Status & 32);

                    Mon_Animate();
                }
                else
                {
	            //bset	#5,obStatus(a1)
                    player.Status = player.Status | 32;

	            //bset	#5,obStatus(a0)
                    obj->Status = obj->Status | 32;
   
	            //bra.s	Mon_Animate
                    Mon_Animate();
                }
            }   //; ===========================================================================
        }
    }       //ends @normal, second case
}

//Mon_Animate:	; Routine 6
void Mon_Animate()
{
    //lea	(Ani_Monitor).l,a1
    byte **aniScript = Ani_Monitor;

    //bsr.w	AnimateSprite
    AnimateSprite(obj, aniScript);

    Mon_Display();
}


//Mon_Display:	; Routine 8
void Mon_Display()
{
    //bsr.w	DisplaySprite
    DisplaySprite(obj);

    //out_of_range	DeleteObject
    if (out_of_range(obj)) { DeleteObject(obj); }

    //rts
}
	
//; ===========================================================================

//Mon_BreakOpen:	; Routine 4
void Mon_BreakOpen()
{
    //addq.b	#2,obRoutine(a0)
    obj->Routine = obj->Routine + 2;

    //move.b	#0,obColType(a0)
    obj->ColType = 0;

    //bsr.w	FindFreeObj
    object *monContents = FindFreeObj();

    //bne.s	Mon_Explode
    if (monContents->ID == 0)
    {
        //move.b	#id_PowerUp,0(a1) ; load monitor contents object
        monContents->ID = id_PowerUp;

	//move.w	obX(a0),obX(a1)
        monContents->X = obj->X;

	//move.w	obY(a0),obY(a1)
        monContents->Y = obj->Y;

	//move.b	obAnim(a0),obAnim(a1)
        monContents->Anim = obj->Anim;
    }

    //Mon_Explode:
    //bsr.w	FindFreeObj
    object *explosion = FindFreeObj();

    //bne.s	@fail
    if (explosion->ID == 0)
    {
        //move.b	#id_ExplosionItem,0(a1) ; load explosion object
        explosion->ID = id_ExplosionItem;

	//addq.b	#2,obRoutine(a1) ; don't create an animal
        explosion->Routine = explosion->Routine + 2;

	//move.w	obX(a0),obX(a1)
        explosion->X = obj->X;

	//move.w	obY(a0),obY(a1)
        explosion->Y = obj->Y;
    }

    //@fail:
    //lea	(v_objstate).w,a2
    byte *statePtr = v_objstate;

    //moveq	#0,d0
    //move.b	obRespawnNo(a0),d0
    byte respawn = obj->RespawnNo;

    #define curMonitor 2+respawn
    //bset	#0,2(a2,d0.w)
    statePtr[curMonitor] = statePtr[curMonitor] | 1;

    //move.b	#9,obAnim(a0)	; set monitor type to broken
    obj->Anim = 9;
	
    //bra.w	DisplaySprite
    DisplaySprite(obj);
}

/*; ---------------------------------------------------------------------------
; Subroutine to	make the sides of a monitor solid
; ---------------------------------------------------------------------------

; ||||||||||||||| S U B	R O U T	I N E |||||||||||||||||||||||||||||||||||||||*/


//Mon_SolidSides:
signed long Mon_SolidSides(object *obj, word width, word belowPlayer, signed short &distPlayerMonX, signed short &distPlayerMonY)
{
    //lea	(v_player).w,a1
    object *sonic = &player;

    //move.w	obX(a1),d0
    //sub.w	obX(a0),d0
    distPlayerMonX = sonic->X - obj->X;
      
    #define distPlayerMonR distPlayerMonX
    #define distPlayerMonL distPlayerMonX
    //add.w	d1,d0
    distPlayerMonR = distPlayerMonX + width;

    //bmi.s	loc_A4E6
    if (distPlayerMonR >= 0)
    {
        #define doubleWidth distPlayerMonY
        //move.w	d1,d3
        //add.w	d3,d3
        doubleWidth = width * 2;

        //cmp.w	d3,d0
        //bhi.s	loc_A4E6
        if (distPlayerMonR <= doubleWidth)
        {
	    //move.b	obHeight(a1),d3
            //ext.w	d3
	    //add.w	d3,d2
            word height = sonic->Height + belowPlayer;
    
	    //move.w	obY(a1),d3
	    //sub.w	obY(a0),d3
            distPlayerMonY = sonic->Y - obj->Y; 

	    #define distPlayerMonB distPlayerMonY
            //add.w	d2,d3
            distPlayerMonB = distPlayerMonY + height;

	    //bmi.s	loc_A4E6
            if (distPlayerMonB >= 0)
            {
		//add.w	d2,d2
		word doubleHeight = height * 2;

                //cmp.w	d2,d3
		//bcc.s	loc_A4E6
                if (distPlayerMonB <= doubleHeight)
                { 
		    //tst.b	(f_lockmulti).w 
                    //bmi.s	loc_A4E6
		    //cmpi.b	#6,(v_player+obRoutine).w
		    //bcc.s	loc_A4E6
                    //tst.w	(v_debuguse).w
		    //bne.s	loc_A4E6
                    if ((!f_lockmulti) && (player.Routine <= 6) && (v_debuguse == 0))
                    {
                        //cmp.w	d0,d1
                        //bcc.s	loc_A4DC
                        if (width < distPlayerMonR)
                        { 
		            //add.w	d1,d1
		            word doubleWidth = width * 2;

                            //sub.w	d1,d0
                            distPlayerMonL = distPlayerMonR - doubleWidth;
                        }
                    
                        //loc_A4DC:
		        //cmpi.w	#$10,d3
                        //bcs.s	loc_A4EA
                        if (distPlayerMonY > 0x10)
                        {
                            //loc_A4EA:
		            //moveq	#0,d1
		            //move.b	obActWid(a0),d1
		            //addq.w	#4,d1
                            word monActionWidth = obj->ActionWidth + 4;

		            //move.w	d1,d2
		            //add.w	d2,d2
                            word dblActionWidth = monActionWidth * 2;
 
               		    //add.w	obX(a1),d1
		            //sub.w	obX(a0),d1
                            signed short distPlayerMonActR = (sonic->X - obj->X) + monActionWidth;

		            //bmi.s	loc_A4E2
                            //cmp.w	d2,d1
		            //bcc.s	loc_A4E2
                            if ((distPlayerMonActR >= 0) && (distPlayerMonActR < dblActionWidth))
                            {
                                //moveq	#-1,d1
		                //rts	
                                return -1;
                            }
                            else
                            {           
                                //loc_A4E2:
		                //moveq	#1,d1
		                //rts
                                return 1;
                            }	                   
		        }
                    }
                }
            }
        }
    }
    
    //loc_A4E6:
    //moveq	#0,d1
    //rts
    return 0;
}   //; End of function Obj26_SolidSides

